package com.own.business.pay.module.wechat.controller;

import com.alibaba.fastjson2.JSON;
import com.own.aop.login.LoginIgnore;
import com.own.business.pay.module.wechat.entity.model.WechatPayResponseModel;
import com.own.business.pay.module.wechat.entity.response.WechatNotifyResponse;
import com.own.business.pay.module.wechat.property.WechatPayProperty;
import com.own.business.pay.module.wechat.service.WechatAppPayService;
import com.own.business.pay.module.wechat.util.WechatResponseDecryptUtil;
import com.own.component.common.base.controller.BaseController;
import com.own.constant.ConstantApiPrefix;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * WechatPayController
 *
 * @author chenxueli
 * @date 2023-08-17 16:42:00
 */
@RestController
@RequestMapping(ConstantApiPrefix.BASE_API_V1_PREFIX + "pay/wechat")
public class WechatPayController extends BaseController {

    @Resource
    private WechatPayProperty wechatPayProperty;
    @Resource
    private WechatAppPayService wechatAppPayService;

    /**
     * 注意：
     * <p>
     * • 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是，当商户系统收到通知进行处理时，先检查对应业务数据的状态，并判断该通知是否已经处理。如果未处理，则再进行处理；如果已处理，则直接返回结果成功。在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱。
     * <p>
     * • 如果在所有通知频率后没有收到微信侧回调，商户应调用查询订单接口确认订单状态。
     * <p>
     * 特别提醒：商户系统对于开启结果通知的内容一定要做签名验证，并校验通知的信息是否与商户侧的信息一致，防止数据泄露导致出现“假通知”，造成资金损失。
     */
    @LoginIgnore
    @PostMapping("callback")
    public WechatNotifyResponse callback(
            @RequestBody WechatPayResponseModel model
    ) {
        // 解析数据
        var eventType = model.getEvent_type();
        if (!"TRANSACTION.SUCCESS".equals(eventType)) {
            return WechatNotifyResponse.fail("[event_type=" + eventType + "]不是 'TRANSACTION.SUCCESS' ");
        }
        var result = new WechatResponseDecryptUtil(wechatPayProperty.getApiKeyV3().getBytes()).decrypt(
                model.getResource().getAssociated_data().getBytes(),
                model.getResource().getNonce().getBytes(),
                model.getResource().getCiphertext()
        );
        // 去通知处理
        var object = JSON.parseObject(result);
        var outTradeNo = object.getString("out_trade_no");
        wechatAppPayService.handlerPayComplete(outTradeNo, object);
        return WechatNotifyResponse.success();
    }

    /**
     * 注意：
     * <p>
     * 对后台通知交互时，如果微信收到应答不是成功或超时，微信认为通知失败，微信会通过一定的策略定期重新发起通知，尽可能提高通知的成功率，但微信不保证通知最终能成功
     * <p>
     * • 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是，当商户系统收到通知进行处理时，先检查对应业务数据的状态，并判断该通知是否已经处理。如果未处理，则再进行处理；如果已处理，则直接返回结果成功。在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱。
     * <p>
     * • 如果在所有通知频率后没有收到微信侧回调。商户应调用查询订单接口确认订单状态。
     * <p>
     * 特别提醒：商户系统对于开启结果通知的内容一定要做签名验证，并校验通知的信息是否与商户侧的信息一致，防止数据泄露导致出现“假通知”，造成资金损失。
     */
    @LoginIgnore
    @PostMapping("refund/callback")
    public WechatNotifyResponse refundCallback(
            @RequestBody WechatPayResponseModel model
    ) {
        // 解析数据
        var eventType = model.getEvent_type();
        if (!"REFUND.SUCCESS".equals(eventType)) {
            return WechatNotifyResponse.fail("[event_type=" + eventType + "]不是 'REFUND.SUCCESS'");
        }
        var result = new WechatResponseDecryptUtil(wechatPayProperty.getApiKeyV3().getBytes()).decrypt(
                model.getResource().getAssociated_data().getBytes(),
                model.getResource().getNonce().getBytes(),
                model.getResource().getCiphertext()
        );
        var object = JSON.parseObject(result);
        var outTradeNo = object.getString("out_trade_no");
        wechatAppPayService.handlerRefundComplete(outTradeNo, object);
        return WechatNotifyResponse.success();
    }

}
